/*
 * Searcher模块
 * 1.需要初始化索引
 * 2.进行关键字搜索查找
 * */
#include<json/json.h>
#include"index.hpp"
namespace ns_searcher{
    struct InvertElemPrint{
        uint16_t doc_id;
        std::vector<std::string> words;
        int weight;
        InvertElemPrint():doc_id(0),weight(0){}
    };
    class Searcher{
        public:
            void InitSearcher(const std::string& input)
            {
                //1.获取或创建索引对象
                ns_index::Index& index_t = ns_index::Index::GetInstance();
                //2.创建索引
                index_t.BuildIndex(input);
            }
            void Search(const std::string& query,std::string*json_string)
            {
                ns_index::Index& index_t = ns_index::Index::GetInstance();
                //对query进行分词
                std::vector<std::string> words;
                ns_util::JiebaUtil::CutString(query,&words);
                //for(auto& s:words)
                //{
                //    std::cout<<s<<std::endl;
                //}

                //统计关键词的倒排拉链
                //ns_index::InvertedList inverted_list_all;

                //建立文档id和InertedElemPrint的映射
                std::unordered_map<uint16_t,InvertElemPrint> tokens_map;
                //统计全部文档ID
                std::vector<InvertElemPrint> inverted_list_all;

                for(std::string& s:words)
                {
                    boost::to_lower(s);
                    //根据关键词获取倒排拉链
                    ns_index::InvertedList* inverted_list = index_t.GetInvertedIndex(s);
                    if(inverted_list == nullptr)
                        continue;
                    //inverted_list_all.insert(inverted_list_all.end(),inverted_list->begin(),inverted_list->end());
                    for(auto& elem:*inverted_list)
                    {
                        auto& item = tokens_map[elem.doc_id];
                        item.doc_id = elem.doc_id;
                        item.weight += elem.weight;
                        item.words.push_back(elem.word);
                    }
                }
                for(auto& elem:tokens_map)
                {
                    inverted_list_all.push_back(std::move(elem.second));
                }
                //对InvertedElem进行排序
//                sort(inverted_list_all.begin(),inverted_list_all.end(),[](const ns_index::InvertedElem& e1,const ns_index::InvertedElem& e2){
//                        return e1.weight > e2.weight;//大于是降序
//                        });
                sort(inverted_list_all.begin(),inverted_list_all.end(),[](const InvertElemPrint& e1,const InvertElemPrint& e2){
                        return e1.weight > e2.weight;//大于是降序
                        });
                //构建json_string
                Json::Value root;
                for(auto& elem:inverted_list_all)
                {
                    ns_index::DocInfo* doc = index_t.GetForwardIndex(elem.doc_id); 
                    if(doc == nullptr)continue;
                    Json::Value item;
                    item["title"] = doc->title;
                    //item["test"] = "test";
                    item["desc"] = GetDesc(doc->content,elem.words[0]);//摘要
                    item["url"] = doc->url;
                    //for debug
                   // item["word"] = elem.word;
                    item["weight"] = elem.weight;
                    root.append(item);
                }
                //Json::FastWriter writer;
                *json_string = root.toStyledString();
            }
            std::string GetDesc(const std::string& html_content,const std::string& word)
            {
                const int prev_step = 50;
                const int end_step = 100;
                auto iter = std::search(html_content.begin(),html_content.end(),word.begin(),word.end(),[](int a,int b){
                        return (std::tolower(a) ==std::tolower(b));
                        });
                if(iter == html_content.end())
                {
                    return "None1";
                }
                //计算迭代器之间的距离
                int pos = std::distance(html_content.begin(),iter);
                int start =0;
                int end = html_content.size();
                if(pos > start + prev_step) start =  pos - prev_step;
                if(end > pos + end_step) end = pos + end_step;
                if(start >= end)return"None2";
                std::string desc =  html_content.substr(start,end-start);
                desc += "......";
                return desc;
            }
    };
}
